/*******************************************
 * Copyright 2007 Aphrodite Framework for javaME .
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Public License v2.0
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
 * Email : owner@aphroditeme.dev.java.net
 * Contributors:
 *     Kent Elton - initial API and implementation
 *******************************************/

package com.aphrodite.io;

import java.io.DataInputStream;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Hashtable;

import javax.microedition.io.Connector;
import javax.microedition.io.HttpConnection;

import com.aphrodite.util.log.ConsoleAppender;
import com.aphrodite.util.log.LogManager;
import com.aphrodite.util.log.Logger;

/**
 * Takes care of HTTP interactions.This class takes care of the dirty work
 * involved in making connections, handling exceptions and clean up.
 * <p>
 * <b>Making a simple http connection</b><br/> <code>
 * class TestHttpCommManager implements CommProcessNotifier{<br/>
 * ..<br/>
 * ..<br/>
 * public void doCommProcess(){<br/>
 * HttpCommManager comm=new HttpCommManager();<br/>
 * comm.setURL("http://wwww.server.com/login?user=user",HttpConnection.GET);</br>
 * comm.setProcessNotifier(this);<br/>
 * Thread thread=new Thread(comm);<br/>
 * thread.start();<br/>
 * }<br/>
 * 
 * <i><font color="green">//CommProcessNotifier implementation</font><i><br/>
 * void setPercent(){<br/>
 * 
 * }<br/>
 * <i><font color="green">//CommProcessNotifier implementation</font><i><br/>
 * void handleResource(InputStream is, long length){<br/>
 * <b>.. do response handling here</b><br/>
 * }<br/>
 * <i><font color="green">//CommProcessNotifier implementation</font><i><br/>
 * void processComplete(boolean success){<br/>
 * }<br/>
 * <i><font color="green">//CommProcessNotifier implementation</font><i><br/>
 * void handleError(String error){<br/>
 *    System.out.println("error occured");<br/>
 * }<br/>
 * 
 * 
 * }
 * </code>
 * </p>
 * 
 * @author kentelt
 */
public class HttpCommManager implements Runnable {

	private static long dataUsage;

	/**
	 * 
	 * 
	 * @return The total data used (in kb) for all Http connections used by this
	 *         class
	 */
	public static String getUsage() {
		return Long.toString(dataUsage / 1024);
	}

	private Logger log = LogManager.getLogger(HttpCommManager.class, ConsoleAppender.getAppender());
	private String method;
	private CommProcessNotifier notifier;
	private Hashtable reqProps = new Hashtable();
	private String url;

	public void addRequestMethod(String method, String value) {
		reqProps.put(method, value);
	}

	public String getURL() {
		return this.url;
	}

	public void run() {

		HttpConnection connection;
		DataInputStream is;
		log.info("Comm Thread started");
		try {
			log.info("Comm URL:" + url);
			connection = (HttpConnection) Connector.open(url);
			connection.setRequestMethod(method);
			// if (connection.getRequestMethod().equals(HttpConnection.POST)) {
			// log.info("The connection type is POST");
			// connection.setRequestProperty("Content-Type",
			// "application/x-www-form-urlencoded");
			// connection.setRequestProperty("Connection", "close");
			// }
			if (!reqProps.isEmpty()) {
				Enumeration keys = reqProps.elements();
				while (keys.hasMoreElements()) {
					String key = (String) keys.nextElement();
					log.info("New request property " + key);
					connection.setRequestProperty(key, (String) reqProps.get(key));
				}
				reqProps.clear();
			}
			int response = connection.getResponseCode();
			if (response == HttpConnection.HTTP_OK) {
				log.info("Getting input stream");
				is = connection.openDataInputStream();
				if (is != null) {
					long data = connection.getLength();
					dataUsage += data;
					notifier.handleResource(is, data);
					is.close();
					connection.close();
					notifier.processComplete(true);
				} else {
					notifier.handleError(0, "InputStream is NULL");
				}
			} else {
				switch (response) {
				case HttpConnection.HTTP_NOT_FOUND:
					notifier.handleError(response, "Resource not found");
					break;
				case HttpConnection.HTTP_NO_CONTENT:
					notifier.handleError(response, "No Content Found");
					break;
				case HttpConnection.HTTP_CLIENT_TIMEOUT:
					notifier.handleError(response, "Your request has timed out!");
					break;
				case HttpConnection.HTTP_INTERNAL_ERROR:// 500
					notifier.handleError(response, "Server has encountered an internal error!");
					break;
				case 413:
					notifier.handleError(response, "The file is too large to handle!");
					break;
				default:
					notifier.handleError(response, " Bad Response from server");
					break;
				}
			}
		} catch (IOException e) {
			log.fatal("I/O Exception", e);
			notifier.handleError(0, "[CommunicationManager]I/O Exception " + e.toString());
		}

	}

	public void setProcessNotifier(CommProcessNotifier notifier) {
		this.notifier = notifier;
	}

	/**
	 * Set the url to use
	 * 
	 * @param url
	 * @param method
	 */
	public void setURL(String url, String method) {
		this.url = url;
		this.method = method;
		if (this.method == HttpConnection.POST) {
			reqProps.put("Connection", "close");
			reqProps.put("Content-Type", "application/x-www-form-urlencoded");
		}
	}
}
